/**
 *	 defined the main entry program
 *   VisualGroup JavaScript prototype Classes, version draf
 *  (c) 2008 Bill Vison <vison_ruan@126.com>
 *
 *
/*--------------------------------------------------------------------------*/
/**
 * 	defined ScriptLoaderImpl
 	class ScriptLoaderImpl {
		function setPrefix($prefixStr);
		function addClasses($classesArray);
		function load();
		function getState();
		
		// --- if load complete will stop
	}
 */
ScriptLoaderImpl = Ext.extend(Ext.util.Observable , {
							  
	_prefix:null,
	
	_loadClasses:null,
	
	/**
	 * the script loader state
	 */
	_state:0,
	
	constructor:function($config) {
		
		// ---- initialize value ---
		this._loadClasses = [];
		
		ScriptLoaderImpl.superclass.constructor.apply(this, arguments);
		
		// --- defined events ---
		this.addEvents({
			// --- afterResponse will be fired after response
			afterResponse:true,
			// --- loaded will be fired after load
			loaded:true
		});
		
		
	},
	
	load : function() {
		
		// ----- defined all load event -----
		this.addListener("afterResponse",function($this , $classState) {
			// --- handle loaded class and remove from array
			$this.getLoadClasses().remove( $classState.className );
			
			// ---- finish to load all class in this script loader ----
			if ( $this.getLoadClasses().length == 0) {
				// --- change the state ---
				$this.setState( ScriptLoaderImpl.STOP );
			}
			

		});
		
		
		// --- change state ---
		this.setState( ScriptLoaderImpl.START );
		
		// --- use thread ---
		var $thread = new Thread( {runnable:this} );
		
		
		$thread.start();
		
	},
	
	/**
	 * use the runnable interface 
	 */
	run:function($this) {

		var $classPath = null;
		var $filePath = null;
		var $class = null;
		var $loadClasses = $this.getLoadClasses();
		
		var $i = 0;
		try {
			for ($i = 0 ; $i <  $loadClasses.length ; $i++) {
				$class = $loadClasses[$i];
				// --- replace all string ---
				var $temp = $class.toString().replace(".","/");
				$oriValue = $class.toString();
				while ($temp != $oriValue) {
					$oriValue = $temp;
					$temp = $oriValue.replace(".","/");
				}
				
				$filePath = $this.getPrefix() + "/js/" + $temp + ".js";
				$this._loadScript($filePath , $class);
			}
			
			// ---- set the state to work ----
			if ( $loadClasses.length > 0 ) {
				$this.setState( ScriptLoaderImpl.LOADING );
			} else {
				// --- stop immediately ---
				$this.setState( ScriptLoaderImpl.STOP );
			}
		
		} catch (ex) {
			
			var $msg = "Change Class path and load script error ! and occur class ["+ $loadClasses[$i]+"] !";
			throw new ScriptLoaderImpl.Exception($msg,null,ScriptLoaderImpl.Exception.LoadingFileException);

		} finally {
			
			$classPath = null;
			
			$filePath = null;
			
			$class = null;			
		}

	},
	
	/**
	 * add classes need to load
	 */
	addClasses : function($classesArray) {
		
		if ($classesArray == null) {
			throw new Exception.SysException("Can not set the class array is null!",null,Exception.NullObjectException);			
		}
		
		var $tmpObj = $classesArray;

		this._loadClasses.push($tmpObj);			

	},
	
	/**
	 * set the loader current state
	 */
	getState : function() {
		return this._state;
	},
	
	setState : function( $state ) {
		this._state = $state;
	},
	
	/**
	 * set the loader prefix (context name)
	 */
	setPrefix : function($prefix) {
		this._prefix = $prefix;
	},
	
	getPrefix : function() {
		return this._prefix;
	},
	
	getLoadClasses : function() {
		return this._loadClasses;
	},
	
	/**
	 * the core load script defined 
	 */
	_loadScript:function($url , $className) {
		//Ext.log("***** start begin ***** , " + $url + " , " + $className);
		Ext.Ajax.request({
			method:"GET", 
			scope:this,
			url:$url,
			
			success: function($response){
				var $res = $response.responseText;
				var $dependentClasses = null;
				var $scriptSrc = null;
				var $cls = null;
				try {
					
					/**
				 	* handle load defined , if will add the mark for the loaded class method
					*/
					$dependentClasses = ScriptLoaderGlobalHandle.findUsingImport($res);

					$scriptSrc = ScriptLoaderGlobalHandle.scriptWithOutUsing($res);
					
					$cls = {className:$className,loaded:true,url:$url,dependentClasses:$dependentClasses.clone(),src:$scriptSrc};
					
					this.fireEvent("loaded" ,this , $cls );

					this.fireEvent("afterResponse" ,this , $cls );

				} catch (ex) {
					var $msg = "Occur by [ScriptLoaderImpl.loadScript] : "+ex;
					if (Ext != null) {
						Ext.log( $msg );
					} else {
						alert($msg)
					}					
					
				} finally {
					/** release variable */
					$dependentClasses = null;
					$scriptSrc = null;
					$cls = null;
					$res = null;
					
				}
				
				
				
			},
			
			failure:function($response) {
				/**
				 * handle load defined , if will add the mark for the loaded class method
				 */
				try {
					this.fireEvent("afterResponse" ,this , {className:$className,loaded:false,url:$url});					
				} catch ( ex ) {
					var $msg = ex;
					if (Ext != null) {
						Ext.log( $msg );
					} else {
						alert($msg)
					}
				}
			}
			
			
		});
	}
	
});


ScriptLoaderImpl.STOP = 0;
ScriptLoaderImpl.START = 1
ScriptLoaderImpl.LOADING = 2;

/**
 * defined some exception for the loader classes manager
 */
ScriptLoaderImpl.Exception = Ext.extend(Exception.SysException,{
	name:"ScriptLoaderImpl.Exception",
	constructor:function($message , $name ,$value) {
		ScriptLoaderImpl.Exception.superclass.constructor.apply(this, arguments);
	}
});
ScriptLoaderImpl.Exception.LoadingFileException = 301;
ScriptLoaderImpl.Exception.LoadScriptHandleException = 302;

// run the function
(function(){
	try {
		Interface.ensureImplements(new ScriptLoaderImpl(), ScriptLoader);	
	} catch (e) {
		Ext.log("Class Implement Error :"+"[ScriptLoaderImpl] , " + e);
	}		  
})();